#!/usr/bin/env node

const fs = require('fs');
const ps = require('path');
require('dotenv').config({ path: ps.resolve(__dirname, '.env') })

const tinify = require('tinify');
const ProgressBar = require('./progress-bar');
const pb = new ProgressBar('Compress Progress: ', 30);

const { program } = require('commander');

program
  .requiredOption('-s, --src <path>', 'the source directory to be compressed')
  .requiredOption('-t, --namestart <number>', 'the compressed file rename start', parseInt)
  .option('-p, --step <number>', 'the rename step', parseInt)
  .option('-d, --dst <number>', 'the destination directory compressed images will be stored')
  .option('-f, --prefix <string>', 'compressed images name prefix')
  .option('-k, --key <string>', 'the key to tinypng api')
  .option('-e, --test <boolean>', 'true to turn on test, just rename and move')

program.parse(process.argv);

const options = program.opts();

options.step = options.step || 1;
options.dst = options.dst || 'optimized'
options.prefix = options.prefix || '';

tinify.key = options.key || process.env.TINYPNGKEY;

const progress = { total: 0, completed: 0, fail: 0, compressing: 0, max: 5 };

function filterAll(srcPath, fileList, extList) {
  const ret = [];

  const uploadList = [];
  let start = options.namestart;
  let step = options.step;

  for (let file of fileList) {
    const ext = ps.extname(file);

    if (!(extList.includes(ext))) {
      continue;
    }

    ret.push(ps.join(srcPath, file));
    uploadList.push(`${options.prefix}${start},${ps.basename(file, ext)}`);
    start += step;
  }

  const msg = uploadList.join('\n');

  fs.writeFileSync(ps.join(srcPath, 'manifest.txt'), msg);

  return ret;
}

let namestart = options.namestart;
function getName() {
  const name = namestart;
  namestart += options.step;
  return `${options.prefix}${name}`;
}

async function minify(path, filename, outfilename) {
  return new Promise((resolve, reject) => {

    if (!options.test) {
      const src = tinify.fromFile(ps.join(path, filename));

      src.toFile(ps.join(path, outfilename), (err, _) => {
        if (err) reject(err);
        else resolve(null);
      });
    } else {
      setTimeout(() => {
        fs.copyFileSync(ps.join(path, filename), ps.join(path, outfilename));
        resolve(null);
      }, 1000);
    }
  });
}

async function minifyall(srcpath, filelist) {
  const queue = filterAll(srcpath, filelist, ['.png', '.jpg']);

  const dst = ps.join(srcpath, options.dst);
  if (!fs.existsSync(dst)) {
    fs.mkdirSync(dst);
  }

  progress.total = queue.length;
  progress.completed = 0;
  progress.fail = 0;
  progress.compressing = 0;

  function start() {
    if ((progress.completed + progress.fail) == progress.total) {
      return;
    }

    if (progress.compressing > progress.max) {
      return;
    }

    const task = queue.pop();

    if (!task) {
      return
    }

    const dir = ps.dirname(task);
    const filename = ps.basename(task);
    const extname = ps.extname(task);
    const outfilename = ps.join(options.dst, getName() + extname);

    progress.compressing += 1;

    minify(
      dir,
      filename,
      outfilename
    )
      .then(res => {
        progress.completed += 1;
        progress.compressing -= 1;

        pb.render(progress);

        start();
      })
      .catch(e => {
        console.error(e);
        progress.fail += 1;

        start();
      });

    start();
  }

  console.log(`We Have ${progress.total} To Compress!`);

  pb.render(progress);
  start();
}


function main() {
  const cwd = process.cwd();
  const src = ps.resolve(cwd, options.src);

  fs.readdir(src, (err, files) => {
    if (err) {
      console.error(err);
      return;
    }

    if (files.length == 0) {
      return;
    }

    minifyall(src, files);
  });
};

main();

